<?php
namespace zake\foundation\stream;

use zake\foundation\able\ProtocolAble;
use zake\foundation\able\stream\DuplexAble;
use zake\foundation\able\stream\DuplexDriverAble;
use zake\foundation\able\stream\ReadAble;
use zake\foundation\able\stream\ReadPointAble;
use zake\foundation\able\stream\RwBufferAble;
use zake\foundation\able\stream\WriteAble;
use zake\foundation\able\stream\WritePointAble;
use zake\foundation\able\traits\PointTrait;
use zake\foundation\able\traits\ReadBufferTrait;
use zake\foundation\able\traits\ReadPointTrait;
use zake\foundation\able\traits\ReadTrait;
use zake\foundation\able\traits\ResourceTrait;
use zake\foundation\able\traits\WriteBufferTrait;
use zake\foundation\able\traits\WritePointTrait;
use zake\foundation\able\traits\WriteTrait;
use zake\foundation\reactor\Reactor;
use zake\helper\Console;


/**
 * Class DuplexStream
 * @package zake\foundation\stream
 *
 *
 */
class DuplexStream implements DuplexAble,RwBufferAble
{
    use ReadBufferTrait,WriteBufferTrait;
    //use ResourceTrait,PointTrait,WritePointTrait,ReadPointTrait,ReadTrait,WriteTrait,ReadBufferTrait,WriteBufferTrait;

    /**
     * driver
     * @var null|DuplexDriverAble
     */
    protected $channelDriver = null;


    /**
     * 构造器
     *
     * @author liu.bin 2020-04-03 11:01
     */
    public static function create(DuplexDriverAble $driver)
    {
        $self = new static($driver);
        return $self;
    }


    /**
     * 构造器
     *
     * Channel constructor.
     * @param DuplexDriverAble $driver
     */
    protected function __construct(DuplexDriverAble $driver)
    {
        $this->channelDriver = $driver;
    }


    /**
     * 可读流
     * @return ReadStream|ReadAble|ReadPointAble
     *
     * @author liu.bin 2020-04-01 08:59
     */
    public function getReadStream()
    {
        return $this->channelDriver->getReadStream();
    }

    /**
     * 可写流
     *
     * @return WriteStream|WriteAble|BufferWriteStream|WritePointAble
     *
     * @author liu.bin 2020-04-01 08:59
     */
    public function getWriteStream()
    {
        return $this->channelDriver->getWriteStream();
    }

    /**
     * 读
     * @return resource
     *
     * @author liu.bin 2020-03-31 16:33
     */
    public function getReadResource()
    {
        return $this->getReadStream()->getReadResource();
    }


    /**
     * 读
     * @return resource
     *
     * @author liu.bin 2020-03-31 16:33
     */
    public function getWriteResource()
    {
        return $this->getWriteStream()->getWriteResource();
    }


    /**
     *
     * @return int
     *
     * @author liu.bin 2020-04-03 00:37
     */
    public function getWriteFd()
    {
        return $this->getWriteStream()->getWriteFd();
    }


    /**
     *
     * @return int
     *
     * @author liu.bin 2020-04-03 00:37
     */
    public function getReadFd()
    {
        return $this->getReadStream()->getReadFd();
    }



    public function closeReadResource()
    {
        return $this->getReadStream()->closeReadResource();
    }


    public function isCloseReadResource()
    {
        return $this->getReadStream()->isCloseReadResource();
    }



    public function closeWriteResource()
    {
        return $this->getWriteStream()->closeWriteResource();
    }


    public function isCloseWriteResource()
    {
        return $this->getWriteStream()->isCloseWriteResource();
    }


    /**
     * 关闭资源
     *
     * @return bool
     * @author liu.bin 2020-03-31 17:03
     */
    public function closeResource()
    {
        $readResource   = $this->getReadResource();
        $writeResource  = $this->getWriteResource();
        // 两种stream可能分，可能合
        if(is_resource($readResource)){
            fclose($readResource);
        }
        if(is_resource($writeResource)){
            fclose($writeResource);
        }

        return true;
    }



    /**
     * 关闭链接
     *
     * @return bool
     * @author liu.bin 2020-03-31 17:03
     */
    public function close($callBack=null)
    {
        if($callBack instanceof \Closure){
            // 执行自定义回调
            $callBack();
        }
        // 移除读监听
        Reactor::removeReadListener($this);
        Reactor::removeWriteListener($this);
        $this->closeReadResource();
        $this->closeWriteResource();
        return true;
    }



    public function init($pid)
    {
        $this->channelDriver->init($pid);
        $this->setReadProtocol($this->getReadStream()->getProtocol());
        $this->setWriteProtocol($this->getWriteStream()->getProtocol());
    }


    public function __destruct()
    {
        Console::success("duplex stream __destruct");
    }


    /**
     * 获取fd
     * @return int
     *
     * @author liu.bin 2020-04-01 00:05
     */
    public function getFd()
    {
        return 0;
    }

    /**
     * 获取资源
     * @return resource
     *
     * @author liu.bin 2020-03-31 23:51
     */
    public function getResource()
    {
        return null;
    }


    /**
     *
     * @param ProtocolAble $protocol
     * @return bool
     *
     * @author liu.bin 2020-04-02 22:21
     */
    public function setProtocol(ProtocolAble $protocol)
    {
        return false;
    }


    /**
     *
     * @return ProtocolAble|null
     *
     * @author liu.bin 2020-04-02 22:21
     */
    public function getProtocol()
    {
        return null;
    }

    /**
     * 设定读取时间
     *
     * @param int|null $time
     * @author liu.bin 2020-03-31 16:43
     */
    public function setReadTime($time = null)
    {
        $this->getReadStream()->setReadTime($time);
    }

    /**
     * 获取上一次接收数据的时间
     *
     * @return int
     * @author liu.bin 2020-03-28 21:18
     */
    public function getReadTime()
    {
        return $this->getReadStream()->getReadTime();
    }

    /**
     *
     * @return mixed
     *
     * @author liu.bin 2020-04-26 15:21
     */
    public function read($length=65535)
    {
        return $this->getReadStream()->read($length);
    }



    /**
     *
     * @return ProtocolAble
     *
     * @author liu.bin 2020-04-02 22:40
     */
    public function getReadProtocol()
    {
        return $this->getReadStream()->getReadProtocol();
    }

    /**
     *
     * @param ProtocolAble $protocol
     * @return bool
     *
     * @author liu.bin 2020-04-02 22:40
     */
    public function setReadProtocol(ProtocolAble $protocol)
    {
        return $this->getReadStream()->setProtocol($protocol);
    }

    /**
     * 资源是否被关闭
     * 一般为连接方关闭
     *
     * @return bool
     *
     * @author liu.bin 2020-04-25 18:49
     */
    public function isCloseResource()
    {
        return true;
    }

    /**
     *
     * @param $sendData
     * @param array $param
     * @return mixed
     *
     * @author liu.bin 2020-04-26 15:30
     */
    public function write($sendData, $param = [])
    {
        return $this->getWriteStream()->write($sendData,$param);
    }

    /**
     * 写入时间
     *
     * @param int|null $time
     * @author liu.bin 2020-03-31 16:43
     */
    public function setWriteTime($time = null)
    {
        $this->getWriteStream()->setWriteTime($time);
    }

    /**
     * 获取上一次写入数据的时间
     *
     * @return int
     * @author liu.bin 2020-03-28 21:18
     */
    public function getWriteTime()
    {
        return $this->getWriteStream()->getWriteTime();
    }



    /**
     *
     * @return ProtocolAble
     *
     * @author liu.bin 2020-04-02 22:40
     */
    public function getWriteProtocol()
    {
        return $this->getWriteStream()->getWriteProtocol();
    }

    /**
     *
     * @param ProtocolAble $protocol
     * @return bool
     *
     * @author liu.bin 2020-04-02 22:40
     */
    public function setWriteProtocol(ProtocolAble $protocol)
    {
        return $this->getWriteStream()->setWriteProtocol($protocol);
    }
}
